/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   Utillity.cs
 * CreateData   :   2023/5/16 17:19:04
 * UnityVersion :   2021.3.20f1c1
 * Description  :   实用工具
************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Main
{
    public static class Utillity
    {
        /// <summary>
        /// <para>比较两个版本大小</para>
        /// <para>如果v1=v2 返回等于 0</para>
        /// <para>如果v1>v2 返回大于 0</para>
        /// <para>如果v1>v2 返回小于 0</para>
        /// </summary>
        /// <param name="v1">版本字符串</param>
        /// <param name="v2">版本字符串</param>
        /// <returns></returns>
        public static int CompareVersions(string v1, string v2)
        {
            Version version1 = new Version(v1);
            Version version2 = new Version(v2);
            return version1.CompareTo(version2);
        }

        /// <summary>
        /// 获取 模型包围盒
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        public static Bounds GetRendererBounds(Transform target)
        {
            List<Renderer> renderers = new List<Renderer>();
            target.GetComponentsInChildren<Renderer>(renderers);
            if (renderers.Count > 0)
            {
                Bounds bounds = renderers[0].bounds;
                for (int i = 1; i < renderers.Count; i++)
                {
                    bounds.Encapsulate(renderers[i].bounds);
                }
                bounds.center -= target.position;
                return bounds;
            }
            else
            {
                return new Bounds(target.position, Vector3.zero);
            }
        }

        /// <summary>
        /// 当前指针是否在UI上面
        /// </summary>
        /// <param name="ID">指针（触控/鼠标）ID</param>
        /// <returns></returns>
        public static bool IsPointerOverUI(int ID = -1)
        {
            return EventSystem.current.IsPointerOverGameObject(ID);
        }

        /// <summary>
        /// 获取屏幕射线击中信息
        /// </summary>
        /// <param name="pos">屏幕坐标</param>
        /// <param name="distance">最大距离</param>
        /// <param name="LayerMask">交互层</param>
        /// <returns></returns>
        public static RaycastHit ScreenToRay(Vector3 pos, float distance, int layer = 0)
        {
            RaycastHit hitInfo;
            Ray ray = Camera.main.ScreenPointToRay(pos);
            Physics.Raycast(ray, out hitInfo, distance, 1 << layer);
            return hitInfo;
        }
        /// <summary>
        /// 打开外部应用程序
        /// </summary>
        /// <param name="appPath">外部应用程序路径</param>
        /// <param name="args">外部应用程序命令行参数 (多个参数使用空格隔开)长度必须小于 32，699。</param>
        /// <param name="isWait">是否等待外部应用程序关闭</param>
        /// <param name="onOutput">当外部应用程序 StandardOutput 流中写入行时发生。(不要执行耗时操作)</param>
        /// <param name="onQuit">当外部应用程序退出时发生</param>
        public static void OpenExternalApp(string appPath, string args = "", bool isWait = false, Action<string> onOutput = null, Action<int> onQuit = null)
        {
            Process process = new Process();
            process.StartInfo.FileName = appPath;
            process.StartInfo.Arguments = args;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            process.StartInfo.UseShellExecute = false;
            // GB2312 Unity打包出来会报错，解决办法 将 \Editor\Data\MonoBleedingEdge\lib\mono\unityjit 所有I18N dll文件添加到项目内
            process.StartInfo.StandardOutputEncoding = Encoding.GetEncoding("GB2312");      // 简体中文 (GB2312)
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.RedirectStandardOutput = true;        // 如果输出应写入 StandardOutput，则为 true；否则为 false。 默认值为 false。
                                                                    // 每次应用程序向其重定向 StandardOutput 流中写入行时发生。
            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                {
                    onOutput?.Invoke(e.Data);
                }
            };
            process.Start();                // 启动流程资源并将其与流程组件关联。
            process.BeginOutputReadLine();  // 在应用程序的重定向 StandardOutput 流上开始进行异步读取操作。
            if (isWait)
            {
                process.WaitForExit();      // 等待应用程序退出，并收集所有输出
            }
            int exitCode = process.ExitCode;// 获取应用程序的退出代码
            onQuit?.Invoke(exitCode);
        }
        /// <summary>
        /// 获取BoxCollider八个顶点 World Position
        /// </summary>
        /// <param name="box">BoxCollider</param>
        /// <returns>前（右上，左上，右下，左下）后（右上，左上，右下，左下）</returns>
        public static Vector3[] GetBoxColliderVertices(BoxCollider box)
        {
            Vector3[] vertices = new Vector3[8];
            for (int i = 0; i < 8; i++)
            {
                vertices[i] = box.transform.TransformPoint(box.center + Vector3.Scale(box.size * 0.5f, new Vector3((i & 1) == 0 ? 1 : -1, (i & 2) == 0 ? 1 : -1, (i & 4) == 0 ? 1 : -1)));
            }
            return vertices;
        }
        /// <summary>
        /// 生成GUID
        /// </summary>
        /// <param name="isHyphen">是否带连接号</param>
        /// <returns></returns>
        public static string CreateID(bool isHyphen = false)
        {
            Guid uniqueId = Guid.NewGuid();
            return uniqueId.ToString(isHyphen ? "D" : "N"); // 将GUID转换为字符串形式
        }

        /// <summary>
        /// 洗牌算法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="array"></param>
        public static void Shuffle<T>(T[] array)
        {
            int n = array.Length;
            for (int i = 0; i < n; i++)
            {
                int j = UnityEngine.Random.Range(i, n);
                T temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }

        /// <summary>
        /// 数值序号转Excel Column
        /// </summary>
        /// <param name="index">1表示“A”往下以此类推</param>
        public static string NumToAlpha(int index)
        {
            if (index <= 0)
            {
                throw new ArgumentException("数字必须大于0");
            }

            StringBuilder result = new StringBuilder();

            while (index > 0)
            {
                index--;
                int remainder = index % 26;
                char letter = (char)(remainder + 'A');
                result.Insert(0, letter);
                index /= 26;
            }

            return result.ToString();
        }
        /// <summary>
        /// Excel Column 转 数值序号
        /// </summary>
        /// <param name="alpha">“A”表示1往下一次类推</param>
        /// <returns></returns>
        public static int AlphaToNum(string alpha)
        {
            int result = 0;
            foreach (char c in alpha)
            {
                result = result * 26 + (c - 'A' + 1);
            }
            return result;
        }
    }
}
